package com.example.dbdoc.service;

import com.example.dbdoc.model.ColumnInfo;
import com.example.dbdoc.model.IndexInfo;
import com.example.dbdoc.model.TableInfo;
import com.example.dbdoc.strategy.DatabaseMetadataStrategy;
import com.example.dbdoc.strategy.PostgreSQLMetadataStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.dbdoc.exception.DatabaseDocException;

import javax.sql.DataSource;
import java.sql.*;
import java.util.*;

/**
 * 数据库元数据服务
 * 
 * @author 系统生成
 * @version 1.0.0
 */
@Service
public class DatabaseMetadataService {
    
    private static final Logger logger = LoggerFactory.getLogger(DatabaseMetadataService.class);
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private DatabaseMetadataStrategy metadataStrategy;
    
    /**
     * 获取数据库中所有表的信息
     */
    public List<TableInfo> getAllTables() {
        logger.info("开始获取数据库中所有表的信息...");
        List<TableInfo> tables = new ArrayList<>();
        
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            String catalog = connection.getCatalog();
            String schema = connection.getSchema();
            
            logger.debug("数据库目录: {}, Schema: {}", catalog, schema);
            
            // 获取所有表
            try (ResultSet rs = metaData.getTables(catalog, schema, "%", new String[]{"TABLE"})) {
                while (rs.next()) {
                    String tableName = rs.getString("TABLE_NAME");
                    // 使用策略模式获取表注释
                    String tableComment = metadataStrategy.getTableComment(connection, tableName);
                    
                    logger.debug("发现表: {} - {}", tableName, tableComment);
                    
                    TableInfo tableInfo = new TableInfo(tableName, tableComment);
                    
                    try {
                        // 获取表的字段信息
                        List<ColumnInfo> columns = getTableColumns(tableName);
                        tableInfo.setColumns(columns);
                        
                        // 获取表的索引信息
                        List<IndexInfo> indexes = getTableIndexes(tableName);
                        tableInfo.setIndexes(indexes);
                        
                        tables.add(tableInfo);
                        logger.debug("表 {} 信息获取完成，字段数: {}, 索引数: {}", 
                                   tableName, columns.size(), indexes.size());
                        
                    } catch (Exception e) {
                        logger.error("获取表 {} 的详细信息时发生错误: {}", tableName, e.getMessage(), e);
                        logger.warn("跳过表 {} 的处理，继续处理其他表", tableName);
                        logger.debug("建议检查表 {} 的权限设置和结构完整性", tableName);
                        // 继续处理其他表，不因单个表失败而中断
                    }
                }
            }
            
        } catch (SQLException e) {
            logger.error("获取数据库表列表时发生错误 - SQL状态: {}, 错误代码: {}", e.getSQLState(), e.getErrorCode());
            logger.error("错误详情: {}", e.getMessage(), e);
            logger.error("可能的原因:");
            logger.error("1. 数据库连接已断开");
            logger.error("2. 用户没有查看表结构的权限");
            logger.error("3. 数据库服务异常");
            throw new DatabaseDocException.DatabaseConnectionException(e.getMessage(), e);
        }
        
        logger.info("成功获取 {} 个表的信息", tables.size());
        return tables;
    }
    
    /**
     * 获取指定表的所有字段信息
     */
    public List<ColumnInfo> getTableColumns(String tableName) {
        logger.debug("获取表 {} 的字段信息...", tableName);
        List<ColumnInfo> columns = new ArrayList<>();
        
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            String catalog = connection.getCatalog();
            
            // 使用LinkedHashMap保持字段顺序
            Map<String, ColumnInfo> columnMap = new LinkedHashMap<>();
            
            // 先通过标准方式获取字段基本信息，按ORDINAL_POSITION排序
            try (ResultSet rs = metaData.getColumns(catalog, null, tableName, "%")) {
                // 临时存储，用于排序
                List<ColumnInfo> tempColumns = new ArrayList<>();
                
                while (rs.next()) {
                    ColumnInfo column = new ColumnInfo();
                    
                    column.setColumnName(rs.getString("COLUMN_NAME"));
                    String dataType = rs.getString("TYPE_NAME");
                    column.setDataType(dataType);
                    column.setNullable("YES".equalsIgnoreCase(rs.getString("IS_NULLABLE")));
                    
                    // 获取原始默认值并格式化
                    String rawDefaultValue = rs.getString("COLUMN_DEF");
                    String formattedDefaultValue = metadataStrategy.formatDefaultValue(rawDefaultValue, dataType);
                    column.setDefaultValue(formattedDefaultValue);
                    
                    // 如果是PostgreSQL且使用序列，提取序列名称
                    if (metadataStrategy instanceof PostgreSQLMetadataStrategy && rawDefaultValue != null && rawDefaultValue.contains("nextval(")) {
                        String sequenceName = PostgreSQLMetadataStrategy.extractSequenceName(rawDefaultValue);
                        column.setSequenceName(sequenceName);
                    }
                    
                    column.setColumnSize(rs.getInt("COLUMN_SIZE"));
                    column.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
                    
                    // 检查是否自增
                    String autoIncrement = rs.getString("IS_AUTOINCREMENT");
                    column.setAutoIncrement("YES".equalsIgnoreCase(autoIncrement));
                    
                    // 获取字段位置用于排序
                    int ordinalPosition = rs.getInt("ORDINAL_POSITION");
                    
                    tempColumns.add(column);
                }
                
                // 按字段在表中的位置排序
                tempColumns.sort((a, b) -> {
                    // 由于我们无法直接从ColumnInfo获取ORDINAL_POSITION，
                    // 我们使用INFORMATION_SCHEMA重新获取完整信息
                    return 0; // 临时保持原顺序，下面会重新排序
                });
                
                // 按顺序放入LinkedHashMap
                for (ColumnInfo column : tempColumns) {
                    columnMap.put(column.getColumnName(), column);
                }
            }
            
            // 使用策略模式获取字段注释和正确的顺序
            metadataStrategy.enhanceColumnInfo(connection, tableName, columnMap);
            
            columns.addAll(columnMap.values());
            
            for (ColumnInfo column : columns) {
                logger.debug("字段: {} - {} - 允许空: {} - 默认值: {} - 注释: {}", 
                           column.getColumnName(), 
                           column.getFullDataType(), 
                           column.isNullable() ? "是" : "否",
                           column.getDefaultValue(),
                           column.getComment());
            }
            
        } catch (SQLException e) {
            logger.error("获取表 {} 的字段信息时发生错误 - SQL状态: {}, 错误代码: {}", tableName, e.getSQLState(), e.getErrorCode());
            logger.error("错误详情: {}", e.getMessage(), e);
            logger.error("建议检查表 {} 是否存在以及是否有访问权限", tableName);
            throw new DatabaseDocException.MetadataReadException(tableName, e.getMessage(), e);
        }
        
        logger.debug("表 {} 共有 {} 个字段", tableName, columns.size());
        return columns;
    }
    
    /**
     * 获取指定表的索引信息
     */
    public List<IndexInfo> getTableIndexes(String tableName) {
        logger.debug("获取表 {} 的索引信息...", tableName);
        Map<String, IndexInfo> indexMap = new HashMap<>();
        
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            String catalog = connection.getCatalog();
            
            // 获取主键信息
            try (ResultSet rs = metaData.getPrimaryKeys(catalog, null, tableName)) {
                while (rs.next()) {
                    String columnName = rs.getString("COLUMN_NAME");
                    short keySeq = rs.getShort("KEY_SEQ");
                    
                    IndexInfo primaryIndex = indexMap.computeIfAbsent("PRIMARY", 
                        k -> new IndexInfo("PRIMARY", "PRIMARY", false));
                    primaryIndex.addColumn(columnName);
                    primaryIndex.setSequence(keySeq);
                    
                    logger.debug("主键字段: {} (序号: {})", columnName, keySeq);
                }
            }
            
            // 获取其他索引信息
            try (ResultSet rs = metaData.getIndexInfo(catalog, null, tableName, false, false)) {
                while (rs.next()) {
                    String indexName = rs.getString("INDEX_NAME");
                    
                    // 跳过主键索引（已经处理过了）
                    if ("PRIMARY".equals(indexName)) {
                        continue;
                    }
                    
                    boolean nonUnique = rs.getBoolean("NON_UNIQUE");
                    String columnName = rs.getString("COLUMN_NAME");
                    short ordinalPosition = rs.getShort("ORDINAL_POSITION");
                    
                    if (indexName != null && columnName != null) {
                        IndexInfo indexInfo = indexMap.computeIfAbsent(indexName, 
                            k -> new IndexInfo(indexName, nonUnique ? "INDEX" : "UNIQUE", !nonUnique));
                        
                        indexInfo.addColumn(columnName);
                        indexInfo.setSequence(ordinalPosition);
                        
                        logger.debug("索引: {} - 字段: {} - 唯一: {} (序号: {})", 
                                   indexName, columnName, !nonUnique ? "是" : "否", ordinalPosition);
                    }
                }
            }
            
        } catch (SQLException e) {
            logger.error("获取表 {} 的索引信息时发生错误 - SQL状态: {}, 错误代码: {}", tableName, e.getSQLState(), e.getErrorCode());
            logger.error("错误详情: {}", e.getMessage(), e);
            logger.warn("将返回空索引列表，继续处理其他信息");
            return new ArrayList<>(); // 返回空列表而不是抛出异常，让文档生成继续进行
        }
        
        List<IndexInfo> indexes = new ArrayList<>(indexMap.values());
        logger.debug("表 {} 共有 {} 个索引", tableName, indexes.size());
        return indexes;
    }
}